// Projector.cpp: implementation of the CProjector class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Projector.h"

//////////////////////////////////////////////////////////////////////
// const
//////////////////////////////////////////////////////////////////////

#define	ZMIN	1.0f
#define	ZMAX	256.0f

//////////////////////////////////////////////////////////////////////
// util function
//////////////////////////////////////////////////////////////////////

PDIRECT3DTEXTURE8 CreateDepthMap( PDIRECT3DDEVICE8 pDevice )
{	
	PDIRECT3DTEXTURE8		pText;
	D3DLOCKED_RECT			rect;

	if( FAILED( pDevice->CreateTexture( 256, 1, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &pText ) ) )
		return NULL;	

	if( FAILED( pText->LockRect( 0, &rect, NULL, 0 ) ) )
	{
		pText->Release();
		return NULL;
	}

	LPDWORD					pPixels = (LPDWORD)rect.pBits;	

	for( DWORD i = 0 ; i < 256 ; i++ )
		pPixels[i] = D3DCOLOR_ARGB( i, 0x0, 0x0, 0x0 );

	pText->UnlockRect( 0 );

	return pText;
}

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CProjector::CProjector( PDIRECT3DDEVICE8 pDevice ) : CEfx( pDevice ),
													 m_pvbProjector( NULL ),
													 m_pvbZoom( NULL ),
													 m_ptexTemp( NULL ),
													 m_ptexDepthMap( NULL ),
													 m_ptrZoom( NULL ),
													 m_piqSpot( NULL ),
													 m_piqGrid( NULL ),
													 m_piqEyes( NULL ),
													 m_piqFade( NULL )
{
	for( DWORD i = 0 ; i < 4 ; i++ )
	{
		m_ptrProjector[i] = NULL;
		m_pvbBeams[i] = NULL;
	}

	try
	{	
		LoadTexture( "mainboard.jpg" );
		LoadTextureWithAlpha( "spot.jpg", "spot_alpha.bmp" );
		LoadTexture( "emiter.jpg" );
		LoadAlphaTexture( "grid.bmp" );
		LoadAlphaTexture( "eyes.bmp" );
	}
	catch( CTextureException )
	{		
		throw CSystemException( "unable to load textures" );
	}

	if( !m_smQuadric.Load( m_pDevice, "data\\objects\\quadric.smf" ) )	
		throw CSystemException( "unable to load quadric.smf" );	

	if( !m_smRing.Load( m_pDevice, "data\\objects\\ring.smf" ) )	
		throw CSystemException( "unable to load ring.smf" );	

	if( FAILED( m_pDevice->CreateVertexBuffer( 4*3*sizeof(VERTEX), 0, FVF_VERTEX, D3DPOOL_DEFAULT, &m_pvbProjector ) ) )	
		throw CSystemException( "unable to create projector vertex buffer" );	

	if( FAILED( m_pDevice->CreateTexture( 64, 64, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_ptexTemp ) ) )	
		throw CSystemException( "unable to create tmp texture buffer" );	

	if( FAILED( m_pDevice->CreateVertexBuffer( 4*6*sizeof(TLVERTEX), 0, FVF_TLVERTEX, D3DPOOL_DEFAULT, &m_pvbZoom ) ) )
		throw CSystemException( "unable to create zoom vertex buffer" );

	if( !( m_ptexDepthMap = CreateDepthMap( m_pDevice ) ) )	
		throw CSystemException( "unable to create depth map" );	

	for( i = 0 ; i < 4 ; i++ )
	{
		if( FAILED( m_pDevice->CreateVertexBuffer( 2*16*16*sizeof(SIMPLEVERTEX), 0, FVF_SIMPLEVERTEX, D3DPOOL_DEFAULT, &m_pvbBeams[i] ) ) )		
			throw CSystemException( "unable to create beams vertex buffer" );		
	}

	for( i = 0 ; i < 4 ; i++ )
		m_ptrProjector[i] = new CTextureRenderer( m_pDevice, TRUE, 64, 64 );

	m_piqSpot = new CImageQuad( m_pDevice, 0, 0, 64, 64 );
	m_piqSpot->SetARGB( 0xffffffff );

	m_piqGrid = new CImageQuad( m_pDevice );
	m_piqGrid->SetColor( 0x0 );

	m_piqEyes = new CImageQuad( m_pDevice, 0, 0, 0, 0 );
	m_piqEyes->SetAlpha( 0x0 );

	m_piqFade = new CImageQuad( m_pDevice );

	m_ptrZoom = new CTextureRenderer( m_pDevice, TRUE, 512, 512 );
	m_bRenderZoom = FALSE;

	he3d_CVector			vProjectors[4];

	vProjectors[0] = he3d_CVector( -2.50f, -1.36f, -1.45f );
	vProjectors[1] = he3d_CVector(  2.50f, -1.36f, -1.45f );
	vProjectors[2] = he3d_CVector(  0.00f, -1.36f,  2.89f );
	vProjectors[3] = he3d_CVector(  0.00f,  2.72f,  0.00f );

	m_vProjectors[0] = 0.333f*( vProjectors[0] + vProjectors[1] + vProjectors[3] );
	m_vProjectors[1] = 0.333f*( vProjectors[0] + vProjectors[2] + vProjectors[3] );
	m_vProjectors[2] = 0.333f*( vProjectors[1] + vProjectors[2] + vProjectors[3] );
	m_vProjectors[3] = 0.333f*( vProjectors[0] + vProjectors[1] + vProjectors[2] );

	m_vOrgin[0] = vProjectors[2];
	m_vOrgin[1] = vProjectors[1];
	m_vOrgin[2] = vProjectors[0];
	m_vOrgin[3] = vProjectors[3];

	PVERTEX					pVertices;	

	m_pvbProjector->Lock( 0, 0, (LPBYTE*)&pVertices, 0 );
	
	*(pVertices++) = VERTEX( vProjectors[0], Normalize( m_vProjectors[0] - m_vOrgin[0] ), 0.0f, 1.0f );
	*(pVertices++) = VERTEX( vProjectors[1], Normalize( m_vProjectors[0] - m_vOrgin[0] ), 1.0f, 1.0f );
	*(pVertices++) = VERTEX( vProjectors[3], Normalize( m_vProjectors[0] - m_vOrgin[0] ), 0.5f, 0.0f );

	*(pVertices++) = VERTEX( vProjectors[0], Normalize( m_vProjectors[1] - m_vOrgin[1] ), 0.0f, 1.0f );
	*(pVertices++) = VERTEX( vProjectors[3], Normalize( m_vProjectors[1] - m_vOrgin[1] ), 1.0f, 1.0f );
	*(pVertices++) = VERTEX( vProjectors[2], Normalize( m_vProjectors[1] - m_vOrgin[1] ), 0.5f, 0.0f );

	*(pVertices++) = VERTEX( vProjectors[1], Normalize( m_vProjectors[2] - m_vOrgin[2] ), 0.0f, 1.0f );
	*(pVertices++) = VERTEX( vProjectors[2], Normalize( m_vProjectors[2] - m_vOrgin[2] ), 1.0f, 1.0f );
	*(pVertices++) = VERTEX( vProjectors[3], Normalize( m_vProjectors[2] - m_vOrgin[2] ), 0.5f, 0.0f );

	*(pVertices++) = VERTEX( vProjectors[0], Normalize( m_vProjectors[3] - m_vOrgin[0] ), 0.0f, 1.0f );
	*(pVertices++) = VERTEX( vProjectors[1], Normalize( m_vProjectors[3] - m_vOrgin[0] ), 1.0f, 1.0f );
	*(pVertices++) = VERTEX( vProjectors[2], Normalize( m_vProjectors[3] - m_vOrgin[0] ), 0.5f, 0.0f );

	m_pvbProjector->Unlock();

	PTLVERTEX				pVerts;

	m_pvbZoom->Lock( 0, 0, (LPBYTE*)&pVerts, 0 );

	*(pVerts++) = TLVERTEX( 0.0f, 0.0f, 0.0f, 0.5f, 0x80ffffff, 0.0f, 0.0f );
	*(pVerts++) = TLVERTEX( 640.0f, 480.0f, 0.0f, 0.5f, 0x80ffffff, 1.0f, 1.0f );
	*(pVerts++) = TLVERTEX( 0.0f, 480.0f, 0.0f, 0.5f, 0x80ffffff, 0.0f, 1.0f );		

	*(pVerts++) = TLVERTEX( 640.0f, 480.0f, 0.0f, 0.5f, 0x80ffffff, 1.0f, 1.0f );
	*(pVerts++) = TLVERTEX( 0.0f, 0.0f, 0.0f, 0.5f, 0x80ffffff, 0.0f, 0.0f );
	*(pVerts++) = TLVERTEX( 640.0f, 0.0f, 0.0f, 0.5f, 0x80ffffff, 1.0f, 0.0f );

	for( i = 1 ; i < 3 ; i++ )
	{
		*(pVerts++) = TLVERTEX( 0.0f, 0.0f, 0.0f, 0.5f, 0x40ffffff, 0.0f, 0.0f );
		*(pVerts++) = TLVERTEX( 640.0f, 480.0f, 0.0f, 0.5f, 0x40ffffff, 1.0f, 1.0f );
		*(pVerts++) = TLVERTEX( 0.0f, 480.0f, 0.0f, 0.5f, 0x40ffffff, 0.0f, 1.0f );		

		*(pVerts++) = TLVERTEX( 640.0f, 480.0f, 0.0f, 0.5f, 0x40ffffff, 1.0f, 1.0f );
		*(pVerts++) = TLVERTEX( 0.0f, 0.0f, 0.0f, 0.5f, 0x40ffffff, 0.0f, 0.0f );
		*(pVerts++) = TLVERTEX( 640.0f, 0.0f, 0.0f, 0.5f, 0x40ffffff, 1.0f, 0.0f );
	}

	m_pvbZoom->Unlock();
		
	for( i = 0 ; i < 4 ; i++ )	
		for( DWORD j = 0 ; j < 256 ; j++ )							
			m_fBaseLenght[i][j] = ( 30.0f + 20.f*RAND() );				

	// sync splines

	m_fSync[0][ 0] = FLOATKEY(  0.00f,  0.00f );
	m_fSync[0][ 1] = FLOATKEY(  0.20f,  0.00f );
	m_fSync[0][ 2] = FLOATKEY(  1.81f,  0.00f );
	m_fSync[0][ 3] = FLOATKEY(  2.01f,  1.00f );
	m_fSync[0][ 4] = FLOATKEY(  2.15f,  0.00f );
	m_fSync[0][ 5] = FLOATKEY(  2.29f,  1.00f );
	m_fSync[0][ 6] = FLOATKEY(  2.47f,  0.00f );
	m_fSync[0][ 7] = FLOATKEY(  2.65f,  1.00f );
	m_fSync[0][ 8] = FLOATKEY(  2.85f,  0.00f );
	m_fSync[0][ 9] = FLOATKEY(  3.00f,  0.00f );
	m_fSync[0][10] = FLOATKEY(  3.20f,  1.00f );
	m_fSync[0][11] = FLOATKEY(  3.30f,  0.00f );
	m_fSync[0][12] = FLOATKEY(  3.39f,  1.00f );
	m_fSync[0][13] = FLOATKEY(  3.52f,  0.00f );
	m_fSync[0][14] = FLOATKEY(  3.65f,  1.00f );
	m_fSync[0][15] = FLOATKEY(  3.85f,  0.00f );
	m_fSync[0][16] = FLOATKEY(  5.32f,  0.00f );
	m_fSync[0][17] = FLOATKEY(  5.52f,  1.00f );
	m_fSync[0][18] = FLOATKEY(  5.72f,  0.00f );
	m_fSync[0][19] = FLOATKEY(  7.95f,  0.00f );
	m_fSync[0][20] = FLOATKEY(  8.15f,  1.00f );
	m_fSync[0][21] = FLOATKEY(  8.35f,  0.00f );
	m_fSync[0][22] = FLOATKEY( 10.19f,  0.00f );
	m_fSync[0][23] = FLOATKEY( 10.39f,  1.00f );
	m_fSync[0][24] = FLOATKEY( 10.49f,  0.00f );
	m_fSync[0][25] = FLOATKEY( 10.58f,  1.00f );
	m_fSync[0][26] = FLOATKEY( 10.62f,  0.00f );
	m_fSync[0][27] = FLOATKEY( 10.66f,  1.00f );
	m_fSync[0][28] = FLOATKEY( 10.86f,  0.00f );
	m_fSync[0][29] = FLOATKEY( 12.71f,  0.00f );
	m_fSync[0][30] = FLOATKEY( 12.91f,  1.00f );
	m_fSync[0][31] = FLOATKEY( 13.11f,  0.00f );
	m_fSync[0][32] = FLOATKEY( 13.16f,  0.00f );
	m_fSync[0][33] = FLOATKEY( 13.36f,  1.00f );
	m_fSync[0][34] = FLOATKEY( 13.56f,  0.00f );
	m_fSync[0][35] = FLOATKEY( 13.69f,  0.00f );
	m_fSync[0][36] = FLOATKEY( 13.89f,  1.00f );
	m_fSync[0][37] = FLOATKEY( 13.93f,  0.00f );
	m_fSync[0][38] = FLOATKEY( 13.98f,  1.00f );
	m_fSync[0][39] = FLOATKEY( 14.18f,  0.00f );
	m_fSync[0][40] = FLOATKEY( 16.04f,  0.00f );
	m_fSync[0][41] = FLOATKEY( 16.24f,  1.00f );
	m_fSync[0][42] = FLOATKEY( 16.44f,  0.00f );
	m_fSync[0][43] = FLOATKEY( 18.21f,  0.00f );
	m_fSync[0][44] = FLOATKEY( 18.41f,  1.00f );
	m_fSync[0][45] = FLOATKEY( 18.61f,  0.00f );
	m_fSync[0][46] = FLOATKEY( 20.01f,  0.00f );
	m_fSync[0][47] = FLOATKEY( 20.21f,  1.00f );
	m_fSync[0][48] = FLOATKEY( 20.41f,  0.00f );
	m_fSync[0][49] = FLOATKEY( 21.63f,  0.00f );
	m_fSync[0][50] = FLOATKEY( 21.83f,  1.00f );
	m_fSync[0][51] = FLOATKEY( 22.03f,  0.00f );


	InitFloatSpline( 52, m_fSync[0] );

	m_fSync[1][ 0] = FLOATKEY(  0.00f,  0.00f );
	m_fSync[1][ 1] = FLOATKEY(  0.20f,  0.00f );
	m_fSync[1][ 2] = FLOATKEY(  1.62f,  0.00f );
	m_fSync[1][ 3] = FLOATKEY(  1.82f,  1.00f );
	m_fSync[1][ 4] = FLOATKEY(  2.02f,  0.00f );
	m_fSync[1][ 5] = FLOATKEY(  3.62f,  0.00f );
	m_fSync[1][ 6] = FLOATKEY(  3.82f,  1.00f );
	m_fSync[1][ 7] = FLOATKEY(  4.02f,  0.00f );
	m_fSync[1][ 8] = FLOATKEY(  5.50f,  0.00f );
	m_fSync[1][ 9] = FLOATKEY(  5.70f,  1.00f );
	m_fSync[1][10] = FLOATKEY(  5.90f,  0.00f );
	m_fSync[1][11] = FLOATKEY(  8.49f,  0.00f );
	m_fSync[1][12] = FLOATKEY(  8.69f,  1.00f );
	m_fSync[1][13] = FLOATKEY(  8.89f,  0.00f );
	m_fSync[1][14] = FLOATKEY(  9.30f,  0.00f );
	m_fSync[1][15] = FLOATKEY(  9.50f,  1.00f );
	m_fSync[1][16] = FLOATKEY(  9.70f,  0.00f );
	m_fSync[1][17] = FLOATKEY(  9.74f,  0.00f );
	m_fSync[1][18] = FLOATKEY(  9.94f,  1.00f );
	m_fSync[1][19] = FLOATKEY( 10.14f,  0.00f );
	m_fSync[1][20] = FLOATKEY( 10.91f,  0.00f );
	m_fSync[1][21] = FLOATKEY( 11.11f,  1.00f );
	m_fSync[1][22] = FLOATKEY( 11.31f,  0.00f );
	m_fSync[1][23] = FLOATKEY( 13.95f,  0.00f );
	m_fSync[1][24] = FLOATKEY( 14.15f,  1.00f );
	m_fSync[1][25] = FLOATKEY( 14.35f,  0.00f );
	m_fSync[1][26] = FLOATKEY( 15.95f,  0.00f );
	m_fSync[1][27] = FLOATKEY( 16.15f,  1.00f );
	m_fSync[1][28] = FLOATKEY( 16.35f,  0.00f );
	m_fSync[1][29] = FLOATKEY( 18.65f,  0.00f );
	m_fSync[1][30] = FLOATKEY( 18.85f,  1.00f );
	m_fSync[1][31] = FLOATKEY( 19.05f,  0.00f );
	m_fSync[1][32] = FLOATKEY( 20.45f,  0.00f );
	m_fSync[1][33] = FLOATKEY( 20.65f,  1.00f );
	m_fSync[1][34] = FLOATKEY( 20.85f,  0.00f );
	m_fSync[1][35] = FLOATKEY( 21.46f,  0.00f );
	m_fSync[1][36] = FLOATKEY( 21.66f,  1.00f );
	m_fSync[1][37] = FLOATKEY( 21.86f,  0.00f );


	InitFloatSpline( 38, m_fSync[1] );

	m_fSync[2][ 0] = FLOATKEY(  0.00f,  0.00f );
	m_fSync[2][ 1] = FLOATKEY(  0.01f,  0.00f );
	m_fSync[2][ 2] = FLOATKEY(  0.01f,  1.00f );
	m_fSync[2][ 3] = FLOATKEY(  0.16f,  0.00f );
	m_fSync[2][ 4] = FLOATKEY(  0.30f,  1.00f );
	m_fSync[2][ 5] = FLOATKEY(  0.50f,  0.00f );
	m_fSync[2][ 6] = FLOATKEY(  1.18f,  0.00f );
	m_fSync[2][ 7] = FLOATKEY(  1.38f,  1.00f );
	m_fSync[2][ 8] = FLOATKEY(  1.47f,  0.00f );
	m_fSync[2][ 9] = FLOATKEY(  1.55f,  1.00f );
	m_fSync[2][10] = FLOATKEY(  1.75f,  0.00f );
	m_fSync[2][11] = FLOATKEY(  3.80f,  0.00f );
	m_fSync[2][12] = FLOATKEY(  4.00f,  1.00f );
	m_fSync[2][13] = FLOATKEY(  4.20f,  0.00f );
	m_fSync[2][14] = FLOATKEY(  5.67f,  0.00f );
	m_fSync[2][15] = FLOATKEY(  5.87f,  1.00f );
	m_fSync[2][16] = FLOATKEY(  6.07f,  0.00f );
	m_fSync[2][17] = FLOATKEY(  8.68f,  0.00f );
	m_fSync[2][18] = FLOATKEY(  8.88f,  1.00f );
	m_fSync[2][19] = FLOATKEY(  8.96f,  0.00f );
	m_fSync[2][20] = FLOATKEY(  9.05f,  1.00f );
	m_fSync[2][21] = FLOATKEY(  9.25f,  0.00f );
	m_fSync[2][22] = FLOATKEY( 11.09f,  0.00f );
	m_fSync[2][23] = FLOATKEY( 11.29f,  1.00f );
	m_fSync[2][24] = FLOATKEY( 11.49f,  0.00f );
	m_fSync[2][25] = FLOATKEY( 11.53f,  0.00f );
	m_fSync[2][26] = FLOATKEY( 11.73f,  1.00f );
	m_fSync[2][27] = FLOATKEY( 11.93f,  0.00f );
	m_fSync[2][28] = FLOATKEY( 11.99f,  0.00f );
	m_fSync[2][29] = FLOATKEY( 12.19f,  1.00f );
	m_fSync[2][30] = FLOATKEY( 12.29f,  0.00f );
	m_fSync[2][31] = FLOATKEY( 12.38f,  1.00f );
	m_fSync[2][32] = FLOATKEY( 12.47f,  0.00f );
	m_fSync[2][33] = FLOATKEY( 12.55f,  1.00f );
	m_fSync[2][34] = FLOATKEY( 12.75f,  0.00f );
	m_fSync[2][35] = FLOATKEY( 14.13f,  0.00f );
	m_fSync[2][36] = FLOATKEY( 14.33f,  1.00f );
	m_fSync[2][37] = FLOATKEY( 14.53f,  0.00f );
	m_fSync[2][38] = FLOATKEY( 15.50f,  0.00f );
	m_fSync[2][39] = FLOATKEY( 15.70f,  1.00f );
	m_fSync[2][40] = FLOATKEY( 15.80f,  0.00f );
	m_fSync[2][41] = FLOATKEY( 15.89f,  1.00f );
	m_fSync[2][42] = FLOATKEY( 16.09f,  0.00f );
	m_fSync[2][43] = FLOATKEY( 16.49f,  0.00f );
	m_fSync[2][44] = FLOATKEY( 16.69f,  1.00f );
	m_fSync[2][45] = FLOATKEY( 16.90f,  0.00f );
	m_fSync[2][46] = FLOATKEY( 17.76f,  0.00f );
	m_fSync[2][47] = FLOATKEY( 17.96f,  1.00f );
	m_fSync[2][48] = FLOATKEY( 18.05f,  0.00f );
	m_fSync[2][49] = FLOATKEY( 18.14f,  1.00f );
	m_fSync[2][50] = FLOATKEY( 18.34f,  0.00f );
	m_fSync[2][51] = FLOATKEY( 19.19f,  0.00f );
	m_fSync[2][52] = FLOATKEY( 19.39f,  1.00f );
	m_fSync[2][53] = FLOATKEY( 19.49f,  0.00f );
	m_fSync[2][54] = FLOATKEY( 19.58f,  1.00f );
	m_fSync[2][55] = FLOATKEY( 19.67f,  0.00f );
	m_fSync[2][56] = FLOATKEY( 19.75f,  1.00f );
	m_fSync[2][57] = FLOATKEY( 19.95f,  0.00f );
	m_fSync[2][58] = FLOATKEY( 20.90f,  0.00f );
	m_fSync[2][59] = FLOATKEY( 21.10f,  1.00f );
	m_fSync[2][60] = FLOATKEY( 21.20f,  0.00f );
	m_fSync[2][61] = FLOATKEY( 21.29f,  1.00f );
	m_fSync[2][62] = FLOATKEY( 21.39f,  0.00f );
	m_fSync[2][63] = FLOATKEY( 21.48f,  1.00f );
	m_fSync[2][64] = FLOATKEY( 21.68f,  0.00f );


	InitFloatSpline( 65, m_fSync[2] );

	m_fSync[3][ 0] = FLOATKEY(  0.00f,  0.00f );
	m_fSync[3][ 1] = FLOATKEY(  0.20f,  0.00f );
	m_fSync[3][ 2] = FLOATKEY(  0.37f,  0.00f );
	m_fSync[3][ 3] = FLOATKEY(  0.57f,  1.00f );
	m_fSync[3][ 4] = FLOATKEY(  0.77f,  0.00f );
	m_fSync[3][ 5] = FLOATKEY(  0.81f,  0.00f );
	m_fSync[3][ 6] = FLOATKEY(  1.01f,  1.00f );
	m_fSync[3][ 7] = FLOATKEY(  1.21f,  0.00f );
	m_fSync[3][ 8] = FLOATKEY(  4.34f,  0.00f );
	m_fSync[3][ 9] = FLOATKEY(  4.54f,  1.00f );
	m_fSync[3][10] = FLOATKEY(  4.74f,  0.00f );
	m_fSync[3][11] = FLOATKEY(  4.98f,  0.00f );
	m_fSync[3][12] = FLOATKEY(  5.18f,  1.00f );
	m_fSync[3][13] = FLOATKEY(  5.26f,  0.00f );
	m_fSync[3][14] = FLOATKEY(  5.34f,  1.00f );
	m_fSync[3][15] = FLOATKEY(  5.54f,  0.00f );
	m_fSync[3][16] = FLOATKEY(  7.59f,  0.00f );
	m_fSync[3][17] = FLOATKEY(  7.79f,  1.00f );
	m_fSync[3][18] = FLOATKEY(  7.99f,  0.00f );
	m_fSync[3][19] = FLOATKEY( 10.72f,  0.00f );
	m_fSync[3][20] = FLOATKEY( 10.92f,  1.00f );
	m_fSync[3][21] = FLOATKEY( 11.12f,  0.00f );
	m_fSync[3][22] = FLOATKEY( 12.62f,  0.00f );
	m_fSync[3][23] = FLOATKEY( 12.82f,  1.00f );
	m_fSync[3][24] = FLOATKEY( 13.02f,  0.00f );
	m_fSync[3][25] = FLOATKEY( 14.40f,  0.00f );
	m_fSync[3][26] = FLOATKEY( 14.60f,  1.00f );
	m_fSync[3][27] = FLOATKEY( 14.74f,  0.00f );
	m_fSync[3][28] = FLOATKEY( 14.89f,  1.00f );
	m_fSync[3][29] = FLOATKEY( 15.09f,  0.00f );
	m_fSync[3][30] = FLOATKEY( 15.13f,  0.00f );
	m_fSync[3][31] = FLOATKEY( 15.33f,  1.00f );
	m_fSync[3][32] = FLOATKEY( 15.53f,  0.00f );
	m_fSync[3][33] = FLOATKEY( 16.31f,  0.00f );
	m_fSync[3][34] = FLOATKEY( 16.51f,  1.00f );
	m_fSync[3][35] = FLOATKEY( 16.71f,  0.00f );
	m_fSync[3][36] = FLOATKEY( 16.94f,  0.00f );
	m_fSync[3][37] = FLOATKEY( 17.14f,  1.00f );
	m_fSync[3][38] = FLOATKEY( 17.34f,  0.00f );
	m_fSync[3][39] = FLOATKEY( 17.40f,  0.00f );
	m_fSync[3][40] = FLOATKEY( 17.60f,  1.00f );
	m_fSync[3][41] = FLOATKEY( 17.69f,  0.00f );
	m_fSync[3][42] = FLOATKEY( 17.79f,  1.00f );
	m_fSync[3][43] = FLOATKEY( 17.99f,  0.00f );
	m_fSync[3][44] = FLOATKEY( 19.82f,  0.00f );
	m_fSync[3][45] = FLOATKEY( 20.02f,  1.00f );
	m_fSync[3][46] = FLOATKEY( 20.22f,  0.00f );

	InitFloatSpline( 47, m_fSync[3] );

	m_fSync[4][ 0] = FLOATKEY(  0.00f,  0.00f );
	m_fSync[4][ 1] = FLOATKEY(  0.20f,  0.00f );
	m_fSync[4][ 2] = FLOATKEY(  9.97f,  0.00f );
	m_fSync[4][ 3] = FLOATKEY( 10.17f,  1.00f );
	m_fSync[4][ 4] = FLOATKEY( 10.24f,  0.00f );
	m_fSync[4][ 5] = FLOATKEY( 10.32f,  1.00f );
	m_fSync[4][ 6] = FLOATKEY( 10.40f,  0.00f );
	m_fSync[4][ 7] = FLOATKEY( 10.48f,  1.00f );
	m_fSync[4][ 8] = FLOATKEY( 10.68f,  0.00f );
	m_fSync[4][ 9] = FLOATKEY( 11.44f,  0.00f );
	m_fSync[4][10] = FLOATKEY( 11.64f,  1.00f );
	m_fSync[4][11] = FLOATKEY( 11.22f,  0.00f );
	m_fSync[4][12] = FLOATKEY( 10.80f,  1.00f );
	m_fSync[4][13] = FLOATKEY( 10.90f,  0.00f );
	m_fSync[4][14] = FLOATKEY( 11.00f,  1.00f );
	m_fSync[4][15] = FLOATKEY( 11.20f,  0.00f );
	m_fSync[4][16] = FLOATKEY( 13.76f,  0.00f );
	m_fSync[4][17] = FLOATKEY( 13.96f,  1.00f );
	m_fSync[4][18] = FLOATKEY( 14.07f,  0.00f );
	m_fSync[4][19] = FLOATKEY( 14.17f,  1.00f );
	m_fSync[4][20] = FLOATKEY( 14.25f,  0.00f );
	m_fSync[4][21] = FLOATKEY( 14.32f,  1.00f );
	m_fSync[4][22] = FLOATKEY( 14.43f,  0.00f );
	m_fSync[4][23] = FLOATKEY( 14.54f,  1.00f );
	m_fSync[4][24] = FLOATKEY( 14.64f,  0.00f );
	m_fSync[4][25] = FLOATKEY( 14.75f,  1.00f );
	m_fSync[4][26] = FLOATKEY( 14.82f,  0.00f );
	m_fSync[4][27] = FLOATKEY( 14.89f,  1.00f );
	m_fSync[4][28] = FLOATKEY( 15.09f,  0.00f );
	m_fSync[4][29] = FLOATKEY( 17.29f,  0.00f );
	m_fSync[4][30] = FLOATKEY( 17.49f,  1.00f );
	m_fSync[4][31] = FLOATKEY( 17.60f,  0.00f );
	m_fSync[4][32] = FLOATKEY( 17.70f,  1.00f );
	m_fSync[4][33] = FLOATKEY( 17.81f,  0.00f );
	m_fSync[4][34] = FLOATKEY( 17.92f,  1.00f );
	m_fSync[4][35] = FLOATKEY( 17.99f,  0.00f );
	m_fSync[4][36] = FLOATKEY( 18.07f,  1.00f );
	m_fSync[4][37] = FLOATKEY( 18.18f,  0.00f );
	m_fSync[4][38] = FLOATKEY( 18.28f,  1.00f );
	m_fSync[4][39] = FLOATKEY( 18.39f,  0.00f );
	m_fSync[4][40] = FLOATKEY( 18.50f,  1.00f );
	m_fSync[4][41] = FLOATKEY( 18.70f,  0.00f );
	m_fSync[4][42] = FLOATKEY( 20.85f,  0.00f );
	m_fSync[4][43] = FLOATKEY( 21.05f,  1.00f );
	m_fSync[4][44] = FLOATKEY( 21.15f,  0.00f );
	m_fSync[4][45] = FLOATKEY( 21.25f,  1.00f );
	m_fSync[4][46] = FLOATKEY( 21.35f,  0.00f );
	m_fSync[4][47] = FLOATKEY( 21.46f,  1.00f );
	m_fSync[4][48] = FLOATKEY( 21.52f,  0.00f );
	m_fSync[4][49] = FLOATKEY( 21.59f,  1.00f );
	m_fSync[4][50] = FLOATKEY( 21.70f,  0.00f );
	m_fSync[4][51] = FLOATKEY( 21.81f,  1.00f );
	m_fSync[4][52] = FLOATKEY( 21.90f,  0.00f );
	m_fSync[4][53] = FLOATKEY( 22.00f,  1.00f );
	m_fSync[4][54] = FLOATKEY( 22.20f,  0.00f );


	InitFloatSpline( 55, m_fSync[4] );

	m_fSync[5][ 0] = FLOATKEY(  0.00f,  0.00f );
	m_fSync[5][ 1] = FLOATKEY(  0.20f,  0.00f );
	m_fSync[5][ 2] = FLOATKEY(  7.63f,  0.00f );
	m_fSync[5][ 3] = FLOATKEY(  7.83f,  1.00f );
	m_fSync[5][ 4] = FLOATKEY(  7.94f,  0.00f );
	m_fSync[5][ 5] = FLOATKEY(  8.05f,  1.00f );
	m_fSync[5][ 6] = FLOATKEY(  8.16f,  0.00f );
	m_fSync[5][ 7] = FLOATKEY(  8.28f,  1.00f );
	m_fSync[5][ 8] = FLOATKEY(  8.36f,  0.00f );
	m_fSync[5][ 9] = FLOATKEY(  8.43f,  1.00f );
	m_fSync[5][10] = FLOATKEY(  8.62f,  0.00f );
	m_fSync[5][11] = FLOATKEY(  8.80f,  2.00f );
	m_fSync[5][12] = FLOATKEY(  9.40f,  0.00f );
	m_fSync[5][13] = FLOATKEY( 11.12f,  0.00f );
	m_fSync[5][14] = FLOATKEY( 11.32f,  1.00f );
	m_fSync[5][15] = FLOATKEY( 11.42f,  0.00f );
	m_fSync[5][16] = FLOATKEY( 11.53f,  1.00f );
	m_fSync[5][17] = FLOATKEY( 11.67f,  0.00f );
	m_fSync[5][18] = FLOATKEY( 11.82f,  1.00f );
	m_fSync[5][19] = FLOATKEY( 11.93f,  0.00f );
	m_fSync[5][20] = FLOATKEY( 12.04f,  1.00f );
	m_fSync[5][21] = FLOATKEY( 12.17f,  0.00f );
	m_fSync[5][22] = FLOATKEY( 12.30f,  2.00f );
	m_fSync[5][23] = FLOATKEY( 12.90f,  0.00f );
	m_fSync[5][24] = FLOATKEY( 14.99f,  0.00f );
	m_fSync[5][25] = FLOATKEY( 15.19f,  1.00f );
	m_fSync[5][26] = FLOATKEY( 15.30f,  0.00f );
	m_fSync[5][27] = FLOATKEY( 15.42f,  1.00f );
	m_fSync[5][28] = FLOATKEY( 15.53f,  0.00f );
	m_fSync[5][29] = FLOATKEY( 15.64f,  1.00f );
	m_fSync[5][30] = FLOATKEY( 15.78f,  0.00f );
	m_fSync[5][31] = FLOATKEY( 15.93f,  1.00f );
	m_fSync[5][32] = FLOATKEY( 16.06f,  0.00f );
	m_fSync[5][33] = FLOATKEY( 16.19f,  2.00f );
	m_fSync[5][34] = FLOATKEY( 16.79f,  0.00f );
	m_fSync[5][35] = FLOATKEY( 18.61f,  0.00f );
	m_fSync[5][36] = FLOATKEY( 18.81f,  1.00f );
	m_fSync[5][37] = FLOATKEY( 18.93f,  0.00f );
	m_fSync[5][38] = FLOATKEY( 19.04f,  1.00f );
	m_fSync[5][39] = FLOATKEY( 19.19f,  0.00f );
	m_fSync[5][40] = FLOATKEY( 19.33f,  1.00f );
	m_fSync[5][41] = FLOATKEY( 19.51f,  0.00f );
	m_fSync[5][42] = FLOATKEY( 19.69f,  1.00f );
	m_fSync[5][43] = FLOATKEY( 19.77f,  0.00f );
	m_fSync[5][44] = FLOATKEY( 19.85f,  2.00f );
	m_fSync[5][45] = FLOATKEY( 20.45f,  0.00f );
	m_fSync[5][46] = FLOATKEY( 22.15f,  0.00f );
	m_fSync[5][47] = FLOATKEY( 22.35f,  1.00f );
	m_fSync[5][48] = FLOATKEY( 22.41f,  0.00f );
	m_fSync[5][49] = FLOATKEY( 22.47f,  1.00f );
	m_fSync[5][50] = FLOATKEY( 22.55f,  0.00f );	
	m_fSync[5][51] = FLOATKEY( 22.65f,  1.00f );
	m_fSync[5][52] = FLOATKEY( 22.85f,  0.00f );

	InitFloatSpline( 53, m_fSync[5] );

	m_dwKeyCount[0] = 52;
	m_dwKeyCount[1] = 38;
	m_dwKeyCount[2] = 65;
	m_dwKeyCount[3] = 47;
	m_dwKeyCount[4] = 55;
	m_dwKeyCount[5] = 48;
}

CProjector::~CProjector()
{
	SAFE_RELEASE( m_pvbProjector );
	SAFE_RELEASE( m_pvbZoom );
	SAFE_RELEASE( m_ptexTemp );
	SAFE_RELEASE( m_ptexDepthMap );

	SAFE_DELETE( m_piqSpot );
	SAFE_DELETE( m_piqGrid );
	SAFE_DELETE( m_piqEyes );
	SAFE_DELETE( m_ptrZoom );

	for( DWORD i = 0 ; i < 4 ; i++ )
	{
		SAFE_RELEASE( m_pvbBeams[i] );
		SAFE_DELETE( m_ptrProjector[i] );
	}
}

BOOL CProjector::UpdateFrame( FLOAT fTime )
{
	// light&material setup

	D3DMATERIAL8			d3dmat;
	
	d3dmat.Ambient.r = 1.0f;
	d3dmat.Ambient.g = 1.0f;
	d3dmat.Ambient.b = 1.0f;
	d3dmat.Diffuse.r = 0.4f;
	d3dmat.Diffuse.g = 0.4f;
	d3dmat.Diffuse.b = 0.4f;
	d3dmat.Emissive.r = 0.1f;
	d3dmat.Emissive.g = 0.1f;
	d3dmat.Emissive.b = 0.1f;
	d3dmat.Specular.r = 1.0f;
	d3dmat.Specular.g = 1.0f;
	d3dmat.Specular.b = 1.0f;
	d3dmat.Power = 100.0f;

	m_pDevice->SetMaterial( &d3dmat );

	D3DLIGHT8				d3dlit;
	
	ZeroMemory( &d3dlit, sizeof(D3DLIGHT8) );

	d3dlit.Type = D3DLIGHT_POINT;	
	d3dlit.Attenuation0 = 1.0f;
	d3dlit.Range = LIGHT_RANGE_MAX;

	d3dlit.Position.x = -150;
	d3dlit.Position.y = 70;
	d3dlit.Position.z = -100;

	d3dlit.Specular.r = 1.0f;
	d3dlit.Specular.g = 1.0f;
	d3dlit.Specular.b = 1.0f;
	d3dlit.Diffuse.r = 1.0f;
	d3dlit.Diffuse.g = 1.0f;
	d3dlit.Diffuse.b = 1.0f;

	m_pDevice->SetLight( 0, &d3dlit );

	d3dlit.Position.x = 100;
	d3dlit.Position.y = -50;
	d3dlit.Position.z = -100;

	m_pDevice->SetLight( 1, &d3dlit );	

	//============================================================================================
	// fxmovement
	//============================================================================================

	for( DWORD i = 0 ; i < 4 ; i++ )
		m_fFalloff[i] = 1.0f - GetFloatSplineValue( fTime, m_dwKeyCount[i], m_fSync[i] );

	FLOAT					fAlpha;

	if( fTime < 2.0f )
	{
		m_bRenderFade = TRUE;

		fAlpha = CLAMPALPHA( 128.0f*(2.0f - fTime ) );
		m_piqFade->SetAlpha( (DWORD)fAlpha );
	}
	else if( fTime > 22.0f )
	{
		m_bRenderFade = TRUE;

		fAlpha = CLAMPALPHA( 128.0f*( fTime - 22.0f ) );
		m_piqFade->SetAlpha( (DWORD)fAlpha );
	}
	else
		m_bRenderFade = FALSE;


	if( fTime > 7.0f && fTime <= 9.0f )
	{
		fAlpha = (9.0f - fTime)*128.0f;
		m_piqEyes->Resize( 520.0f - 128.0f - fAlpha, 380.0f - 128.0f - fAlpha, 520.0f + 128.0f + fAlpha, 380.0f + 128.0f + fAlpha );

		fAlpha = CLAMPALPHA( 128.0f*(fTime - 7.0f) );
		m_piqEyes->SetAlpha( (DWORD)fAlpha );
	}
	else if( fTime > 9.0f )
	{
		m_piqEyes->Resize( 520.0f - 128.0f, 380.0f - 128.0f, 520.0f + 128.0f, 380.0f + 128.0f );
		m_piqEyes->SetAlpha( 0xff );
	}

	PTLVERTEX				pVertices;
	DWORD					dwColor;

	if( fTime > 7.6f )
	{
		m_bRenderZoom = TRUE;

		fAlpha = GetFloatSplineValue( fTime, 53, m_fSync[5] ) + GetFloatSplineValue( fTime, 55, m_fSync[4] );

		dwColor = (DWORD)(2.0f*fAlpha + 64.0f);
		dwColor = D3DCOLOR_ARGB( dwColor, 0xff, 0xff, 0xff );

		fAlpha = GetFloatSplineValue( fTime, 53, m_fSync[5] ) - 0.5f*GetFloatSplineValue( fTime, 55, m_fSync[4] );

		m_pvbZoom->Lock( 0, 0, (LPBYTE*)&pVertices, 0 );		

		for( i = 1 ; i < 4 ; i++ )
		{
			pVertices[i*6+0].m_fU = 0.0f + 0.01f*(FLOAT)i*fAlpha;
			pVertices[i*6+0].m_fV = 0.0f + 0.01f*(FLOAT)i*fAlpha;
			pVertices[i*6+0].m_dwColor = dwColor;

			pVertices[i*6+1].m_fU = 1.0f - 0.01f*(FLOAT)i*fAlpha;
			pVertices[i*6+1].m_fV = 1.0f - 0.01f*(FLOAT)i*fAlpha;
			pVertices[i*6+1].m_dwColor = dwColor;

			pVertices[i*6+2].m_fU = 0.0f + 0.01f*(FLOAT)i*fAlpha;
			pVertices[i*6+2].m_fV = 1.0f - 0.01f*(FLOAT)i*fAlpha;			
			pVertices[i*6+2].m_dwColor = dwColor;

			pVertices[i*6+3].m_fU = 1.0f - 0.01f*(FLOAT)i*fAlpha;
			pVertices[i*6+3].m_fV = 1.0f - 0.01f*(FLOAT)i*fAlpha;
			pVertices[i*6+3].m_dwColor = dwColor;

			pVertices[i*6+4].m_fU = 0.0f + 0.01f*(FLOAT)i*fAlpha;
			pVertices[i*6+4].m_fV = 0.0f + 0.01f*(FLOAT)i*fAlpha;
			pVertices[i*6+4].m_dwColor = dwColor;

			pVertices[i*6+5].m_fU = 1.0f - 0.01f*(FLOAT)i*fAlpha;
			pVertices[i*6+5].m_fV = 0.0f + 0.01f*(FLOAT)i*fAlpha;
			pVertices[i*6+5].m_dwColor = dwColor;
		}
		
		m_pvbZoom->Unlock();
	}

	fTime *= 0.75f;

	m_mtxRing[0] = ScaleMtx( 0.15f )*RotationMtx( 0.5f*fTime, fTime, -fTime );
	m_mtxRing[1] = ScaleMtx( 0.20f )*RotationMtx( -fTime, 0.5f*fTime, fTime );

	m_mtxProjector = ScaleMtx( 3.0f )*RotationMtx( -0.5f*fTime, -fTime, 0.5f*fTime );

	m_mtxCube = RotationMtx( 0.25f*fTime, -0.25f*fTime, 0.2f*fTime );

	m_mtxLights[0] = CameraMtx( m_vOrgin[0]*m_mtxProjector, m_vProjectors[0]*m_mtxProjector, 0 );
	m_mtxLights[1] = CameraMtx( m_vOrgin[1]*m_mtxProjector, m_vProjectors[1]*m_mtxProjector, 0 );
	m_mtxLights[2] = CameraMtx( m_vOrgin[2]*m_mtxProjector, m_vProjectors[2]*m_mtxProjector, 0 );
	m_mtxLights[3] = CameraMtx( m_vOrgin[3]*m_mtxProjector, m_vProjectors[3]*m_mtxProjector, 0 );

	m_mtxBeams[0] = InverseCameraMtx( m_mtxLights[0] );

	// projector rendering

	he3d_CMatrix			mtxDepthMap = IdentMtx();	
	he3d_CMatrix			mtxTmp = IdentMtx();		

	// przeksztalca wspolrzedna ekranowa na wpolrzedna uv dla textury glebokosci
	// dla z = zmin (zmin z maciezy projekcji daje uv = (0.0f, 0.0f) dla z = zmax
	// daje uv = (1.0f, 0.0f) (innymi slowy skaluje zeta z przedzialu zmin - zmax
	// na przedzial 0 - 1, przy okazji przenos z na wsporzdedna x (czyli u dla textury)
	// i zeruje wsporzedna y czyli v dla textury	

	// a tak dla jasnosci kolejne pola maciezy maja postac ._ij gdzie i to numer wiersza a j kolumny
	mtxDepthMap._33 = 1.0f/(ZMAX - ZMIN);
	mtxDepthMap._43 = ZMIN/(ZMAX - ZMIN);
	
	mtxTmp._11 = 0.0f;
	mtxTmp._31 = 1.0f;	

	mtxDepthMap = mtxDepthMap*mtxTmp;

	m_pDevice->SetTransform( D3DTS_PROJECTION, ProjectionMtx( 30.0f, 1.0f, ZMIN, ZMAX ) );

	m_pDevice->SetRenderState( D3DRS_LIGHTING, FALSE );		
	m_pDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_FLAT );
	m_pDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );

	for( i = 0 ; i < 4 ; i++ )
	{
		m_ptrProjector[i]->SetTarget( m_pDevice );
		m_pDevice->Clear( 0, 0, D3DCLEAR_ZBUFFER, 0x0, 1.0f, 0 );

		m_pDevice->BeginScene();

		m_pDevice->SetTexture( 0, GetTexture( "spot.jpg" ) );		
		m_piqSpot->Render( m_pDevice );				

		m_pDevice->SetTexture( 0, m_ptexDepthMap );		
		m_pDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 );
		m_pDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION );
		m_pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
		
		m_pDevice->SetTransform( D3DTS_VIEW, m_mtxLights[i] );	
		m_pDevice->SetTransform( D3DTS_TEXTURE0, mtxDepthMap );

		m_pDevice->SetRenderState( D3DRS_ZENABLE, TRUE );

		for( DWORD j = 0 ; j < 2 ; j++ )
		{
			m_pDevice->SetTransform( D3DTS_WORLD, m_mtxRing[j] );
			m_smRing.Render( m_pDevice );
		}	

		m_pDevice->SetRenderState( D3DRS_ZENABLE, FALSE );

		m_pDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
		m_pDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_PASSTHRU );
		m_pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );

		m_pDevice->EndScene();

		m_ptrProjector[i]->RestoreTarget( m_pDevice );
	}

	// some temporary tables
	static he3d_CVector		vRays[4][256];	
	static FLOAT			fRaysColor[4][256];

	D3DLOCKED_RECT			d3dlrRect;		
	DWORD					dwIndex;

	PDIRECT3DSURFACE8		psurfSrc;
	PDIRECT3DSURFACE8		psurfDest;

	he3d_CMatrix			mtxInv;
	he3d_CVector			vOrg;
	he3d_CVector			vPos = he3d_CVector( 0.0f, 0.0f, 3.75f );
	he3d_CVector			v;
	
	// funcking texture lock.... oh well i do what man has to do :)
	// and man has to do: at first copy render target texture to previously created
	// temporary texture (may be placed in sys mem) this step is necesary becaus
	// render target texture must be created in default mem pool and default mem pool
	// textures are not lockable :)
	for( i = 0 ; i < 4 ; i++ )
	{
		m_ptrProjector[i]->GetTargetTexture()->GetSurfaceLevel( 0, &psurfSrc );
		m_ptexTemp->GetSurfaceLevel( 0, &psurfDest );

		m_pDevice->CopyRects( psurfSrc, NULL, 0, psurfDest, NULL );

		psurfSrc->Release();
		psurfDest->Release();		

		m_ptexTemp->LockRect( 0, &d3dlrRect, NULL, 0 );

		mtxInv = InverseMtx( m_mtxLights[i] );
		vOrg = m_vOrgin[i]*m_mtxProjector;

		dwIndex = 0;

		for( DWORD j = 0 ; j < 16 ; j++ )
		{									
			LPDWORD			pdwLine = (LPDWORD)( (LPBYTE)d3dlrRect.pBits + j*4*d3dlrRect.Pitch );

			for( DWORD k = 0 ; k < 16 ; k++, dwIndex++ )
			{
				FLOAT		fLength = (4.0f*(FLOAT)j - 30.0f)*(4.0f*(FLOAT)j - 30.0f) + (4.0f*(FLOAT)k - 30.0f)*(4.0f*(FLOAT)k - 30.0f);

				if( fLength > 28.0f*28.0f )
				{
					vRays[i][dwIndex] = he3d_CVector( 0.0f, 0.0f, 0.0f );
					continue;
				}				

				DWORD		dwAlpha = 0xff;

				//each ray cover 4 by 4 pixels square

				for( DWORD m = 0 ; m < 4 ; m++ )
					for( DWORD n = 0 ; n < 4 ; n++ )
					{					
						if( dwAlpha > ( ( pdwLine[k*4 + n + (d3dlrRect.Pitch>>2)*m]>>24 )&0xff ) )
							dwAlpha = ( pdwLine[k*4 + n + (d3dlrRect.Pitch>>2)*m]>>24 )&0xff;
					}				

				vPos.x =  ( 4.0f*(FLOAT)k - 30.0f )/32.0f;
				vPos.y = -( 4.0f*(FLOAT)j - 30.0f )/32.0f;

				v = Normalize( vPos*mtxInv - vOrg );

				if( dwAlpha == 0xff )
				{				
					vRays[i][dwIndex] = m_fBaseLenght[i][dwIndex]*v;
					fRaysColor[i][dwIndex] = 0.0f;
				}
				else
				{								
					vRays[i][dwIndex] = ( (FLOAT)dwAlpha - 8.0f )*v;
					fRaysColor[i][dwIndex] = 32.0f;
				}
			}
		}

		m_ptexTemp->UnlockRect( 0 );
	}
	
	PSIMPLEVERTEX			pVerts;	

	for( i = 0 ; i < 4 ; i++ )
	{			
		m_pvbBeams[i]->Lock( 0, 0, (LPBYTE*)&pVerts, 0 );			

		dwIndex = 0;

		for( DWORD j = 0 ; j < 16 ; j++ )
			for( DWORD k  = 0 ; k < 16 ; k++, dwIndex++ )
			{	
				dwColor = (DWORD)CLAMPALPHA( m_fFalloff[i]*80.0f );
				*(pVerts++) = SIMPLEVERTEX( m_vOrgin[i]*m_mtxProjector, D3DCOLOR_XRGB( dwColor, dwColor, dwColor ) );

				dwColor = (DWORD)CLAMPALPHA( m_fFalloff[i]*fRaysColor[i][dwIndex] );
				*(pVerts++) = SIMPLEVERTEX( vRays[i][dwIndex], D3DCOLOR_XRGB( dwColor, dwColor, dwColor ) );				
			}		

		m_pvbBeams[i]->Unlock();
	}	

	// standard setup

	m_pDevice->SetTransform( D3DTS_PROJECTION, ProjectionMtx( 30.0f, 0.75f, 1.0f, 500.0f ) );
	m_pDevice->SetTransform( D3DTS_VIEW, CameraMtx( he3d_CVector( 0, 0, -100 ), he3d_CVector( 0, 0, 3 ), 0 ) );	

	return TRUE;
}

BOOL CProjector::RenderEfx()
{	
	if( m_bRenderZoom )
	{
		m_pDevice->Clear( 0, 0, D3DCLEAR_TARGET, 0x0, 0.0f, 0 );	
		m_ptrZoom->SetTarget( m_pDevice );
		m_pDevice->Clear( 0, 0, D3DCLEAR_ZBUFFER, 0xffffff, 1.0f, 0 );	
	}
	else
		m_pDevice->Clear( 0, 0, D3DCLEAR_ZBUFFER, 0xffffff, 1.0f, 0 );	

	m_pDevice->SetRenderState( D3DRS_ZWRITEENABLE, D3DZB_TRUE );

	m_pDevice->SetRenderState( D3DRS_NORMALIZENORMALS, TRUE );

	m_pDevice->SetRenderState( D3DRS_ZENABLE, D3DZB_FALSE );
	m_pDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
	m_pDevice->SetRenderState( D3DRS_AMBIENT, 0x808080 );

	m_pDevice->SetTexture( 0, GetTexture( "mainboard.jpg" ) );	

	m_pDevice->SetTransform( D3DTS_WORLD, ScaleMtx( 40.0f )*m_mtxCube );	
	m_smQuadric.Render( m_pDevice );	

	m_pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
	m_pDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
	m_pDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );	
	m_pDevice->SetRenderState( D3DRS_CLIPPLANEENABLE, D3DCLIPPLANE0 );	
	
	m_pDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE );
	m_pDevice->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION );
	m_pDevice->SetTextureStageState( 1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT4 | D3DTTFF_PROJECTED );	
	m_pDevice->SetTextureStageState( 1, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP );
	m_pDevice->SetTextureStageState( 1, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP );
	
	he3d_CMatrix			mtx;
	he3d_CVector			vec;
	FLOAT					fPlane[4];
	DWORD					dwColor;

	for( DWORD i = 0 ; i < 4 ; i++ )
	{	
		vec = Normalize( m_vProjectors[i]*m_mtxProjector - m_vOrgin[i]*m_mtxProjector );

		if( vec.z < 0.0f )
			continue;

		mtx = TranslationMtx( 0, 0, -100.0f )*m_mtxLights[i]*ProjectionMtx( 50.0f, 1.0f, 1.0f, 1000.0f )*ScaleMtx( 0.5f, -0.5f, 1.0f )*TranslationMtx( 0.5f, 0.5f, 0.0f );

		fPlane[0] = vec.x;
		fPlane[1] = vec.y;
		fPlane[2] = vec.z;
		fPlane[3] = -35.0f;		

		m_pDevice->SetClipPlane( 0, fPlane );

		dwColor = (DWORD)( CLAMPALPHA(m_fFalloff[i]*255.0f) );

		m_pDevice->SetRenderState( D3DRS_AMBIENT, D3DCOLOR_XRGB( dwColor, dwColor, dwColor ) );

		m_pDevice->SetTexture( 1, m_ptrProjector[i]->GetTargetTexture() );

		m_pDevice->SetTransform( D3DTS_TEXTURE1, mtx );
		m_smQuadric.Render( m_pDevice );
	}

	m_pDevice->SetRenderState( D3DRS_CLIPPLANEENABLE, FALSE );
	m_pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
	
	m_pDevice->SetRenderState( D3DRS_AMBIENT, 0x0 );

	m_pDevice->SetTexture( 0, NULL );
	m_pDevice->SetTexture( 1, NULL );	
	m_pDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE );
	m_pDevice->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 1|D3DTSS_TCI_PASSTHRU );
	m_pDevice->SetTextureStageState( 1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
	m_pDevice->SetTextureStageState( 1, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP );
	m_pDevice->SetTextureStageState( 1, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP );

	m_pDevice->LightEnable( 0, TRUE );
	m_pDevice->LightEnable( 1, TRUE );
	
	m_pDevice->SetRenderState( D3DRS_ZENABLE, D3DZB_USEW );
	m_pDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
	m_pDevice->SetRenderState( D3DRS_SPECULARENABLE, TRUE );	
	m_pDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_FLAT );	

	for( i = 0 ; i < 2 ; i++ )
	{
		m_pDevice->SetTransform( D3DTS_WORLD, m_mtxRing[i] );
		m_smRing.Render( m_pDevice );
	}	

	m_pDevice->LightEnable( 0, FALSE );
	m_pDevice->LightEnable( 1, FALSE );
	
	m_pDevice->SetRenderState( D3DRS_NORMALIZENORMALS, FALSE );
	m_pDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
	m_pDevice->SetRenderState( D3DRS_SPECULARENABLE, FALSE );
	m_pDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD );

	m_pDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );

	m_pDevice->SetTexture( 0, GetTexture( "emiter.jpg" ) );

	m_pDevice->SetTransform( D3DTS_WORLD, m_mtxProjector );

	m_pDevice->SetVertexShader( FVF_VERTEX );
	m_pDevice->SetStreamSource( 0, m_pvbProjector, sizeof(VERTEX) );	
	m_pDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 4 );

	m_pDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );
	
	m_pDevice->SetTexture( 0, NULL );

	m_pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
	m_pDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
	m_pDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );	

	m_pDevice->SetTransform( D3DTS_PROJECTION, ProjectionMtx( 30.0f, 0.75f, 1.0f, 500.0f ) );
	m_pDevice->SetTransform( D3DTS_VIEW, CameraMtx( he3d_CVector( 0, 0, -100 ), he3d_CVector( 0, 0, 3 ), 0 ) );	
	m_pDevice->SetTransform( D3DTS_WORLD, IdentMtx() );

	m_pDevice->SetVertexShader( FVF_SIMPLEVERTEX );

	for( i = 0 ; i < 4 ; i++ )	
	{	
		m_pDevice->SetStreamSource( 0, m_pvbBeams[i], sizeof(SIMPLEVERTEX) );	
		m_pDevice->DrawPrimitive( D3DPT_LINELIST, 0, 16*16 );
	}	

	m_pDevice->SetRenderState( D3DRS_ZENABLE, D3DZB_FALSE );
	m_pDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );

	if( m_bRenderZoom )
	{
		m_ptrZoom->RestoreTarget( m_pDevice );		

		m_pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
		m_pDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
		m_pDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );	

		m_pDevice->SetTexture( 0, m_ptrZoom->GetTargetTexture() );
		m_pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
		m_pDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );

		m_pDevice->SetVertexShader( FVF_TLVERTEX );
		m_pDevice->SetStreamSource( 0, m_pvbZoom, sizeof(TLVERTEX) );
		m_pDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 4*2 );

		m_pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
		m_pDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
	}

	m_pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
	m_pDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
	m_pDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );	

	m_pDevice->SetTexture( 0, GetTexture( "grid.bmp" ) );
	m_pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );

	m_piqGrid->Render( m_pDevice );

	m_pDevice->SetTexture( 0, GetTexture( "eyes.bmp" ) );
	m_pDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
	m_piqEyes->Render( m_pDevice );

	m_pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
	m_pDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );

	if( m_bRenderFade )
	{
		m_pDevice->SetTexture( 0, NULL );
		m_pDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
		m_pDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );	

		m_piqFade->Render( m_pDevice );
	}

	m_pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );	

	return TRUE;
}
